# coding=utf-8
# author='kungege21'
# date=2023/8/3 17:31
from datetime import datetime, date
from pathlib import Path
from typing import List, Optional

from pydantic import BaseModel, ValidationError, constr
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.orm import declarative_base

"""
使用Python的类型注解来进行数据校验和settings管理
Pydantic可以在代码运行时提供类型提示，数据校验失败时提供友好的错误提示
定义数据应该如何在纯规范的Python代码中保存，并用Pydantic验证它
Pydantic types: https://docs.pydantic.dev/latest/usage/types/types/
"""


# Pydantic 实例类
class User(BaseModel):
    id: int  # 无默认值，必填字段
    name: str = "John Snow"  # 有默认值，选填字段
    signup_ts: Optional[datetime] = None
    friends: List[int] = []  # 列表中原始是int类型或者可以直接转换成int类型


external_data = {
    "id": "123",
    "signup_ts": "2023-08-03 17:38",
    "friends": [1, 2, "3"]
}
print("\033[31m 1. ---Pydantic基本用法---\033[0m")
user = User(**external_data)  # 解包的形式实例化
print(user.id, user.friends)
print(repr(user.signup_ts))
print(user.model_dump())

print("\033[31m 2. ---校验失败处理---\033[0m")
try:
    User(id=1, signup_ts=datetime.today(), friends=[1, 2, "not number"])
except ValidationError as e:
    print(e.json())

print("\033[31m 3. ---模型类的属性和方法---\033[0m")
print(user)
print(user.model_dump())
print(user.model_dump_json())
print(user.model_copy())
print(User.model_validate(obj=external_data))  # 替代parse_obj

print(User.model_validate_json('{"id": "124","signup_ts": "2023-08-03 17:38","friends": [1, 2, "3"]}'))  # 替换parse_raw
path = Path('pydantic_tutorial.json')
path.write_text('{"id": "123","signup_ts": "2023-08-3 17:38","friends": [1, 2, "3"]}')
# print(User.parse_file(path))
print(user.model_json_schema())  # schema
# print(user.schema_json())

print("\033[31m 4. ---递归模型---\033[0m")


class Sound(BaseModel):
    sound: str


class Dog(BaseModel):
    birthday: date
    weight: float = Optional[None]
    sound: List[Sound]


s1 = Sound(sound='wang wang')
s2 = Sound(sound='si si')
dogs = Dog(birthday=date.today(), weight=6.6, sound=[s1, s2])
print(dogs.model_dump())

print("\033[31m 5. ---ORM模型：从类实例创建符合ORM对象的模型---\033[0m")

Base = declarative_base()


class CompanyOrm(Base):
    __tablename__ = 'companies'     # 表名
    id = Column(Integer, primary_key=True, nullable=False)
    public_key = Column(String(20), index=True, nullable=False, unique=True)
    name = Column(String(63), unique=True)
    domains = Column(ARRAY(String(255)))


class CompanyMode(BaseModel):
    id: int
    public_key: constr(max_length=20)   # 限制字符长度
    name: constr(max_length=63)
    domains: List[constr(max_length=255)]

    class Config:                       # 固定格式
        from_attributes = True


co_orm = CompanyOrm(
    id=123,
    public_key='foobar',
    name='Testing',
    domains=['example.com', 'imooc.com']
)
print(CompanyMode.model_validate(co_orm))
